package com.flyqiu.form.model;

import com.alibaba.fastjson2.JSONArray;
import com.flyqiu.common.tools.FlyQiuStreamTools;
import com.flyqiu.form.common.FlyQiuFormConstant;
import com.flyqiu.form.model.vo.SqlColumnVo;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 表示表单列信息的数据模型。
 */
public class FlyQiuColumnInfo implements FlyQiuFormConstant.FormBaseColumns {

    @Getter
    private List<SqlColumnModel> addLists = new ArrayList<>();
    @Getter
    private List<SqlColumnVo> editColumns = new ArrayList<>();
    @Getter
    private List<SqlColumnModel> deleteColumns = new ArrayList<>();
    @Getter
    private boolean isUpdateTable;

    // 忽略的列类型
    private static final Set<String> IGNORE_COL_TYPES = new HashSet<>(Arrays.asList("title", "dynamic"));

    // 初始化静态字段
    static {
        IGNORE_COL_TYPES.addAll(Arrays.asList("title", "dynamic"));
    }

    /**
     * 构造函数，初始化新的表单列信息。
     *
     * @param newColumn 新的列数据
     * @param oldColumn 旧的列数据
     */
    public FlyQiuColumnInfo(JSONArray newColumn, List<SqlColumnModel> oldColumn) {
        List<AvueSqlColumnModel> newColumnModel;
        try {
            newColumnModel = newColumn.toJavaList(AvueSqlColumnModel.class).stream()
                    .filter(e -> !IGNORE_COL_TYPES.contains(e.getComponent()))
                    .collect(Collectors.toList());
        } catch (Exception e) {
            throw new IllegalArgumentException("Failed to convert JSONArray to List<AvueSqlColumnModel>", e);
        }
        analysis(oldColumn, newColumnModel);
        this.isUpdateTable = computeIsUpdateTable();
    }

    /**
     * 分析新旧列数据，确定新增、编辑和删除的列。
     *
     * @param oldColumn 旧的列数据
     * @param newColumn 新的列数据
     */
    private void analysis(List<SqlColumnModel> oldColumn, List<? extends SqlColumnModel> newColumn) {
        Map<String, SqlColumnModel> oldColMap = mapOldColumns(oldColumn);
        Set<String> newFields = new HashSet<>();
        processNewColumns(newColumn, oldColMap, newFields);
        updateDeleteColumns(oldColumn, newFields);
    }

    /**
     * 将旧的列数据映射成 Map，便于查找。
     *
     * @param oldColumn 旧的列数据
     * @return 映射后的 Map
     */
    private Map<String, SqlColumnModel> mapOldColumns(List<SqlColumnModel> oldColumn) {
        return oldColumn.stream()
                .filter(FlyQiuStreamTools.distinctByKey(SqlColumnModel::getRealProp))
                .collect(Collectors.toMap(SqlColumnModel::getProp, e -> e));
    }


    /**
     * 处理新的列数据，确定新增和编辑的列。
     *
     * @param newColumn 新的列数据
     * @param oldColMap 旧的列数据映射
     * @param newFields 新的字段集合
     */
    private void processNewColumns(List<? extends SqlColumnModel> newColumn, Map<String, SqlColumnModel> oldColMap, Set<String> newFields) {
        for (SqlColumnModel col : newColumn) {
            if (StringUtils.isNotBlank(col.getId()) && !Objects.equals(col.getProp(), col.getId())) {
                SqlColumnVo editCol = new SqlColumnVo(col);
                editCol.setOldProp(col.getId());
                editColumns.add(editCol);
                newFields.add(editCol.getProp());
                newFields.add(editCol.getId());
                continue;
            }
            SqlColumnModel oldCol = oldColMap.get(col.getProp());
            if (oldCol == null) {
                addLists.add(col);
                newFields.add(col.getProp());
                continue;
            }
            if (col.isMatch(oldCol)) {
                newFields.add(col.getProp());
                continue;
            }
            SqlColumnVo editCol = new SqlColumnVo(col);
            editCol.setOldProp(oldCol.getProp());
            editColumns.add(editCol);
            newFields.add(col.getProp());
        }
    }

    /**
     * 更新删除的列列表。
     *
     * @param oldColumn 旧的列数据
     * @param newFields 新的字段集合
     */
    private void updateDeleteColumns(List<SqlColumnModel> oldColumn, Set<String> newFields) {
        deleteColumns = oldColumn.stream()
                .filter(e -> !newFields.contains(SqlColumnModel.getRealProp(e)))
                .collect(Collectors.toList());
    }

    /**
     * 计算是否需要更新表结构。
     *
     * @return 是否需要更新表结构
     */
    private boolean computeIsUpdateTable() {
        return !addLists.isEmpty() || !editColumns.isEmpty() || !deleteColumns.isEmpty();
    }

    /**
     * 判断是否需要更新表结构。
     *
     * @return 是否需要更新表结构
     */
    public boolean isUpdateTable() {
        return isUpdateTable;
    }
}
